/**
 * Copyright (c) 2009-2011, chunquedong(YangJiandong)
 * 
 * This file is part of ChunMap project
 * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE(Version >=3)
 * 
 * History:
 *     2010-05-05  Jed Young  Creation
 */
package chunmap.model.relate;

import chunmap.model.geom.AbstractGeometry;
import chunmap.model.geom.GeoPoint;
import chunmap.model.geom.Geometry;
import chunmap.model.geom.GeometryCollection;
import chunmap.model.geom.LineString;
import chunmap.model.geom.Polygon;
import chunmap.model.relate.relateop.LineString_LineString;
import chunmap.model.relate.relateop.LineString_Polygon;
import chunmap.model.relate.relateop.Multi2Multi;
import chunmap.model.relate.relateop.Point_LineString;
import chunmap.model.relate.relateop.Point_Point;
import chunmap.model.relate.relateop.Point_Polygon;
import chunmap.model.relate.relateop.Polygon_Polygon;

/**
 * 计算九交矩阵工厂
 * @author chunquedong
 * 
 */
public class ComputeImFactory {

	private static ComputeImFactory instance;

	private ComputeImFactory() {
	}

	public static ComputeImFactory getInstance() {
		if (instance == null) {
			instance = new ComputeImFactory();
		}
		return instance;
	}

	public ComputeIm getImComputer(Geometry g1, Geometry g2) {
		if (g1 instanceof GeoPoint) {
			GeoPoint p1 = (GeoPoint) g1;
			return pointTo(p1, g2);
		} else if (g1 instanceof LineString) {
			LineString l1 = (LineString) g1;
			return lineTo(l1, g2);

		} else if (g1 instanceof Polygon) {
			Polygon a1 = (Polygon) g1;
			return polygonTo(a1, g2);
		} else if (g1 instanceof GeometryCollection) {
			return multiTo(g1, g2);
		} else {
			throw new UnsupportedOperationException();
		}
	}

	public ComputeIm pointTo(GeoPoint p1, Geometry g2) {
		if (g2 instanceof GeoPoint) {
			GeoPoint p2 = (GeoPoint) g2;
			return new Point_Point(p1, p2);
		} else if (g2 instanceof LineString) {
			LineString l2 = (LineString) g2;
			return new Point_LineString(p1, l2);

		} else if (g2 instanceof Polygon) {
			Polygon a2 = (Polygon) g2;
			return new Point_Polygon(p1, a2);
		} else if (g2 instanceof GeometryCollection) {
			return multiTo(p1, g2);
		} else {
			throw new UnsupportedOperationException();
		}

	}

	public ComputeIm lineTo(LineString l1, Geometry g2) {
		if (g2 instanceof GeoPoint) {
			GeoPoint p2 = (GeoPoint) g2;
			return new Point_LineString(p2, l1).setReverse(true);
		} else if (g2 instanceof LineString) {
			LineString l2 = (LineString) g2;
			return new LineString_LineString(l1, l2);

		} else if (g2 instanceof Polygon) {
			Polygon a2 = (Polygon) g2;
			return new LineString_Polygon(l1, a2);
		} else if (g2 instanceof GeometryCollection) {
			return multiTo(l1, g2);
		} else {
			throw new UnsupportedOperationException();
		}
	}

	public ComputeIm polygonTo(Polygon a1, Geometry g2) {
		if (g2 instanceof GeoPoint) {
			GeoPoint p2 = (GeoPoint) g2;
			return new Point_Polygon(p2, a1).setReverse(true);
		} else if (g2 instanceof LineString) {
			LineString l2 = (LineString) g2;
			return new LineString_Polygon(l2, a1).setReverse(true);

		} else if (g2 instanceof Polygon) {
			Polygon a2 = (Polygon) g2;
			return new Polygon_Polygon(a1, a2);
		} else if (g2 instanceof GeometryCollection) {
			return multiTo(a1, g2);
		} else {
			throw new UnsupportedOperationException();
		}
	}

	public ComputeIm multiTo(Geometry g1, Geometry g2) {
		return new Multi2Multi(((AbstractGeometry)g1).toGeometryCollection()
				, ((AbstractGeometry)g2).toGeometryCollection());
	}
}